# -*- encoding: utf-8 -*-
"""
@File  :   lhcenter.py
@Time  :   2021-09-22 13:49
蓝华erp注册服务
"""
import win32serviceutil
import win32service
import win32event
from flask import Flask
from flask import request
import sys
import os
import zipfile
import requests
import shutil
import re
import threading
import time
import datetime
import logging
import inspect
import subprocess
from threading import Timer
from logging.handlers import TimedRotatingFileHandler
import uuid
import hashlib
import win32api


# 获取计算机唯一标识码
def getCid():
    mac = uuid.uuid1()
    mac = mac.__str__()
    mac = mac.split("-")[-1]

    orgKey = f"lherp2021{mac}"

    _md5 = hashlib.md5()
    _md5.update(orgKey.encode(encoding='utf-8'))
    md5Str = _md5.hexdigest()
    return md5Str


# 获取当前路径
def getCurrentPath():
    path = sys.argv[0].split('\\')
    path.pop()
    path = '\\'.join(path) + "\\"
    return path


def getEarliestBakDate():
    # 获取最早备份日期
    scripts = "select 'EarliestDate '+convert(varchar(10),dateadd(day,-nvalue,getdate()),112)+' EarliestDate ' from sys_option where ctype='bak_date_num_max'"
    scripts += "\ngo\n"
    res = executeSql(scripts)
    if res['result']:
        lis = re.findall("EarliestDate.*EarliestDate", res['data'])
        return lis[0].split()[1]
    return False


def updatebakend(dbname):
    # 更新最后备份成功时间
    t = time.strftime("%Y-%m-%d %H:%M", time.localtime())
    scripts = "update qx_database set ddatetime_end='%s' where cdbname='%s'" % (
        t, dbname)
    scripts += "\ngo\n"
    res = executeSql(scripts)


def getBakPath():
    # 获取备份路径
    scripts = "select 'bakpath '+cvalue+' bakpath' from sys_option where ctype='bak_path'"
    scripts += "\ngo\n"
    res = executeSql(scripts)
    if res['result']:
        lis = re.findall("bakpath.*bakpath", res['data'])
        return lis[0].split()[1]
    return False


def bakFileExists(path, fname):
    if not os.path.exists(path):
        os.makedirs(path)
    return os.path.exists(fname)


def backup(dbname, fname):
    # 备份数据库
    scripts = "dump tran {0} with no_log".format(dbname)
    scripts += "\ngo\n"
    scripts += "dump database {0} to '{1}'".format(dbname, fname)
    scripts += "\ngo\n"
    res = executeSql(scripts)
    return res['data']


def executeSql(scripts):
    # 检查备份时间，获取备份ID
    currentpath = getCurrentPath() + "tmpscript.sql"
    try:
        with open(currentpath, 'w') as f:
            f.write(scripts)
    except BaseException as e:
        return {'result': False, 'data': e}
    try:
        resStr = ""
        cmdlines = "isql.exe -Usa  -Psqlsql  -i %s " % currentpath
        with subprocess.Popen(cmdlines,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT,
                              stdin=subprocess.DEVNULL) as res:
            resStr = res.stdout.read()
            resStr = str(resStr, encoding='gbk')
        return {'result': True, 'data': resStr}
    except BaseException as e:
        return {'result': False, 'data': e}


def copytree(src, dst, symlinks=False):
    names = os.listdir(src)
    if not os.path.isdir(dst):
        os.makedirs(dst)
    errors = []
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks)
            else:
                if os.path.isdir(dstname):
                    os.rmdir(dstname)
                elif os.path.isfile(dstname):
                    os.remove(dstname)
                shutil.copy2(srcname, dstname)

        except (IOError, os.error) as why:
            errors.append((srcname, dstname, str(why)))
        except OSError as err:
            errors.extend(err.args[0])
    try:
        shutil.copystat(src, dst)
    except WindowsError:
        # can't copy file access times on Windows
        pass
    except OSError as why:
        errors.extend((src, dst, str(why)))
    if errors:
        raise Error(errors)


def getserviceState(serviceName):
    # 获取服务状态
    try:
        resStr = ''
        cmdlines = 'net start'
        with subprocess.Popen(cmdlines,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT,
                              stdin=subprocess.DEVNULL) as res:
            resStr = res.stdout.read()
            resStr = str(resStr, encoding='gbk')
            return False if resStr.find(serviceName) == -1 else True
    except BaseException as e:
        return False


def get_url_file(url):
    # 下载文件函数
    # 下载到临时目录，如果临时目录不存在就创建一个
    download_path = "D:\\tmp\\%s" % (time.time())
    if os.path.exists(download_path):
        pass
    else:
        os.makedirs(download_path)
    res = requests.get(url, stream=True)
    # 解析文件名
    # 比如url为：http://www.ftp.com/test.zip 那么文件名就是test.zip
    filename = "%s\\%s" % (download_path, url.split('/')[-1])
    with open(filename, "wb") as pdf:
        for chunk in res.iter_content(chunk_size=1024):
            if chunk:
                pdf.write(chunk)
        return {'filename': filename, 'download_path': download_path}


def un_zip(file_name, dest_path):
    # 解压文件
    zip_file = zipfile.ZipFile(file_name)
    file_pre = file_name.split('\\')[-1].split('.')[0]
    for names in zip_file.namelist():
        zip_file.extract(names, dest_path)
    zip_file.close()
    return (dest_path + '\\' + file_pre)


class myservice(win32serviceutil.ServiceFramework):
    # windows服务名称相关
    _svc_name_ = 'lhcenter'  # 任务管理器中显示的服务名
    _svc_display_name_ = '蓝华Erp授权服务'  # 服务管理器中显示的名称
    _svc_description_ = '蓝华Erp应用接口中心'  # 服务管理器中显示的说明

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.logger = self._getLogger()
        self.stop_event = win32event.CreateEvent(None, 0, 0, None)
        self.port = 50123

    def _getLogger(self):
        '''日志记录'''
        logger = logging.getLogger('@')
        this_file = inspect.getfile(inspect.currentframe())
        dirpath = os.path.abspath(os.path.dirname(this_file))
        if os.path.isdir('c:\\log'):  # 创建log文件夹
            pass
        else:
            os.mkdir('c:\\log')
        dir = 'c:\\log'
        handler = TimedRotatingFileHandler(os.path.join(dir, "lhcenter.log"),
                                           when="midnight",
                                           interval=1,
                                           backupCount=20)
        # formatter = logging.Formatter(
        #   '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        formatter = logging.Formatter(
            '%(asctime)s %(levelname)-8s %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        logger.setLevel(logging.INFO)
        return logger

    # 服务程序主逻辑
    def SvcDoRun(self):
        logwriter = self.logger
        app = Flask(__name__)

        @app.route('/getcid', methods=['GET', 'POST'])
        def getcid():
            # 返回计算机唯一标识码
            return getCid()

        @app.route('/', methods=['GET', 'POST'])
        def showver():
            # 返回主服务版本号
            logwriter.info('call func:showver')
            if request.method == "GET":
                return "20201023"

        logwriter.info("lhcenter 服务启动")
        # 启动flask 监听本地端口 响应请求
        app.run(host='0.0.0.0', port=self.port)

    # 停止服务
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.stop_event)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
        self.logger.info("lhcenter 服务停止")


if __name__ == '__main__':
    import sys
    import servicemanager

    import ctypes
    whnd = ctypes.windll.kernel32.GetConsoleWindow()
    if whnd != 0:
        ctypes.windll.user32.ShowWindow(whnd, 0)
        ctypes.windll.kernel32.CloseHandle(whnd)
    if len(sys.argv) == 1:
        # myservice 为服务的类名称 需要与上方声明一致
        try:
            evtsrc_dll = os.path.abspath(servicemanager.__file__)
            servicemanager.PrepareToHostSingle(myservice)
            servicemanager.Initialize('myservice', evtsrc_dll)
            servicemanager.StartServiceCtrlDispatcher()
        except win32service.error as details:
            import winerror
            if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
                win32serviceutil.usage()
    else:
        win32serviceutil.HandleCommandLine(myservice)
